﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Framework
{
    [RequireComponent(typeof(Button))]
    public class ButtonTrigger : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
    {
        private static readonly AnimationCurve ClickDownAnimationCurve = new AnimationCurve(
            new Keyframe(0f, 1f), new Keyframe(0.1f, 1.1f));

        private const float ClickDownAnimationDuration = 0.1f;

        private static readonly AnimationCurve ClickUpAnimationCurve = new AnimationCurve(
            new Keyframe(0f, 1.1f), new Keyframe(0.05f, 1f));

        private const float ClickUpAnimationDuration = 0.05f;

        [HideInInspector] public Button button;

        private float _lastAnimateTime = -1f;
        private bool _isClickDown;
        private bool _isClick;
        private bool _isClickUp;
        private bool _isPlay;
        private Vector3 _sourceScale;
        
        private List<UIClickListener> _listCsharpListener = new List<UIClickListener>();

        public static ButtonTrigger Get(Transform transform)
        {
            ButtonTrigger trigger = transform.GetComponent<ButtonTrigger>();
            if (trigger == null)
            {
                trigger = transform.gameObject.AddComponent<ButtonTrigger>();
            }
            return trigger;
        }

        public void Awake()
        {
            button = GetComponent<Button>();
            ColorBlock colorBlock = new ColorBlock();
            colorBlock.normalColor = Color.white;
            colorBlock.highlightedColor = Color.white;
            colorBlock.pressedColor = Color.white;
            colorBlock.disabledColor = Color.gray;
            colorBlock.colorMultiplier = 1f;
            colorBlock.fadeDuration = 0f;
            button.colors = colorBlock;
            _sourceScale = transform.localScale;
//            button.onClick.AddListener(OnButtonClick);
        }

        private void Update()
        {
            if (_isPlay)
            {
                if (_isClickDown)
                {
                    if (_lastAnimateTime < 0f)
                    {
                        _lastAnimateTime = Time.realtimeSinceStartup;
                    }
                    else
                    {
                        float deltaTime = Time.realtimeSinceStartup - _lastAnimateTime;
                        if (deltaTime > ClickDownAnimationDuration)
                        {
                            deltaTime = ClickDownAnimationDuration;
                        }
                        float scale = ClickDownAnimationCurve.Evaluate(deltaTime);
                        Vector3 vec3;
//                        vec3.x = vec3.y = vec3.z = scale;
                        vec3.x = scale * _sourceScale.x;
                        vec3.y = scale * _sourceScale.y;
                        vec3.z = scale * _sourceScale.z;
                        transform.localScale = vec3;
                        if (deltaTime >= ClickDownAnimationDuration)
                        {
                            _isClickDown = false;
                            _lastAnimateTime = -1f;
                            //                            InvokeClickListener();
                        }
                    }
                }
                if (!_isClickDown && _isClickUp)
                {
                    if (_lastAnimateTime < 0f)
                    {
                        _lastAnimateTime = Time.realtimeSinceStartup;
                    }
                    else
                    {
                        float deltaTime = Time.realtimeSinceStartup - _lastAnimateTime;
                        if (deltaTime > ClickUpAnimationDuration)
                        {
                            deltaTime = ClickUpAnimationDuration;
                        }
                        float scale = ClickUpAnimationCurve.Evaluate(deltaTime);
                        Vector3 vec3;
//                        vec3.x = vec3.y = vec3.z = scale;
                        vec3.x = scale * _sourceScale.x;
                        vec3.y = scale * _sourceScale.y;
                        vec3.z = scale * _sourceScale.z;
                        transform.localScale = vec3;
                        if (deltaTime >= ClickUpAnimationDuration)
                        {
                            _isClickUp = false;
                            _lastAnimateTime = -1f;
                            if (_isClick)
                            {
                                _isClick = false;
                                InvokeClickListener();
                            }
                        }
                    }
                }
                if (!_isClickDown && !_isClickUp)
                {
                    _isPlay = false;
                }
            }
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            if (button.interactable && !_isPlay)
            {
                _isClickDown = true;
                _isPlay = true;
                _lastAnimateTime = -1f;
            }
        }

        public void OnPointerClick(PointerEventData eventData)
        {
            if (button.interactable && !_isPlay || _isClickDown || _isClickUp)
            {
                _isClick = true;
            }
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            if (button.interactable && !_isPlay || _isClickDown)
            {
                _isClickUp = true;
                _isPlay = true;                
            }
        }

        void OnDestroy()
        {
            this._listCsharpListener = null;
        }

        public void InvokeClickListener()
        {
            int count = _listCsharpListener.Count;
            for (int i = 0; i < count; ++i)
            {
                UIClickListener clickListener = _listCsharpListener[i];
                clickListener.Invoke();
            }
        }

        public void AddClickListener(Action<object[]> callback, params object[] args)
        {
            int index = FindCSharpListener(callback);
            if (index == -1)
            {
                UIClickListener clickListener = new UIClickListener(callback, args);
                _listCsharpListener.Add(clickListener);
            }
        }

        public void RemoveClickListener(Action<object[]> callback)
        {
            int index = FindCSharpListener(callback);
            if (index != -1)
            {
                _listCsharpListener.RemoveAt(index);
            }
        }

        private int FindCSharpListener(Action<object[]> callback)
        {
            int count = _listCsharpListener.Count;
            for (int i = 0; i < count; ++i)
            {
                UIClickListener clickListener = _listCsharpListener[i];
                if (clickListener.Equals(callback))
                {
                    return i;
                }
            }
            return -1;
        }
    }
}